@哈哈鱼
4年前 提问
1个回答

如何仅为我的应用设置密码 / PIN

我正在开发一个需要通过为用户设置 passcode/password/pin 来设置安全性功能的应用程序,以便每当他们从后台打开应用程序时,该应用程序都会要求输入 passcode/password/pin 。

我已经设置了将 passcode/pin 保存为共享首选项的逻辑,但是我不确定何时询问。我知道我们无法用 passcode/pin 活动来替换初始屏幕,因为有时从应用程序的homeScreen / MainActivity中,用户按下主屏幕按钮,当他们再次从最近的应用程序中打开该应用程序时,该应用程序应该要求密码/固定密码来恢复应用使用。

任何帮助,将不胜感激。

在下炳尚
4年前

这是一个有趣的问题,我将分享我对这个问题的想法并给出解决方案。

术语:

应用锁类型:密码/密码/密码/密码等的通用名称(在以下部分中,我将使用密码名称进行演示)

PinActivity:一个屏幕,用户可以在其中输入自己的密码以验证自己

故事:

对于需要用户输入图钉的应用,他们通常希望确保敏感信息不会被其他人泄露/窃取。因此,我们将应用程序活动分为两类。

  • 正常活动:通常不包含任何敏感信息,通常在用户登录到应用程序之前,例如SplashActivity,LoginActivity,RegistrationActivity,PinActivity等。

  • 安全活动:通常在用户登录后包含敏感信息,例如MainActivity,HomeActivity,UserInfoActivity等。

条件:

对于安全活动,我们必须通过显示PinActivity确保用户在查看内容之前始终输入他们的密码。在以下情况下将显示此活动:

  • [1]当用户打开安全活动时,形成一个正常活动,例如从SplashActivity到MainActivity

  • [2]当用户通过点击通知打开安全活动时,例如他们点击通知以打开MainActivity

  • [3]当用户从“最近”屏幕中点击应用程序时

  • [4]当应用从其他地方(如服务,广播接收器等)开始安全活动时。

实现方式:

对于情况[1] [2]和[4],在开始安全活动之前,我们将向原始意图添加额外的内容。我将创建一个名为IntentUtils.kt的文件

IntentUtils.kt

const val EXTRA_IS_PIN_REQUIRED = "EXTRA_IS_PIN_REQUIRED"

fun Intent.secured(): Intent {
    return this.apply {
        putExtra(EXTRA_IS_PIN_REQUIRED, true)
    }
}

从正常活动,通知,服务等中使用此类。

startActivity(Intent(this, MainActivity::class.java).secured())

对于情况[3],我将使用2个API:

  • ProcessLifecycleOwner:检测应用程序是否进入后台。典型的情况是用户单击设备上的Home / Menu键。

  • ActivityLifecycleCallbacks:通过依赖onActivityResumed(activity)方法来检测是否恢复活动。

首先,我创建一个基础活动,所有正常的活动性炎症都必须从此类开始

BaseActivity.kt

open class BaseActivity : AppCompatActivity() {

    // This method indicates that a pin is required if 
    // users want to see the content inside.
    open fun isPinRequired() = false
}

其次,我创建一个安全活动,所有安全活动都必须从此类扩展

SecuredActivity.kt

open class SecuredActivity : BaseActivity() {
    override fun isPinRequired() = true

    // This is useful when launch a secured activity with 
    // singleTop, singleTask, singleInstance launch mode
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
    }
}

第三,我创建一个从Application扩展的类,所有逻辑都在该类内部

MyApplication.kt

class MyApplication : Application() {

    private var wasEnterBackground = false

    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(ActivityLifecycleCallbacksImpl())
        ProcessLifecycleOwner.get().lifecycle.addObserver(LifecycleObserverImpl())
    }

    private fun showPinActivity() {
        startActivity(Intent(this, PinActivity::class.java))
    }

    inner class LifecycleObserverImpl : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onEnterBackground() {
            wasEnterBackground = true
        }
    }

    inner class ActivityLifecycleCallbacksImpl : ActivityLifecycleCallbacks {

        override fun onActivityResumed(activity: Activity) {
            val baseActivity = activity as BaseActivity
            if (!wasEnterBackground) {
                // Handle case [1] [2] and [4]
                val removed = removeIsPinRequiredKeyFromActivity(activity)
                if (removed) {
                    showPinActivity()
                }
            } else {
                // Handle case [3]
                wasEnterBackground = false
                if (baseActivity.isPinRequired()) {
                    removeIsPinRequiredKeyFromActivity(activity)
                    showPinActivity()
                }
            }
        }

        private fun removeIsPinRequiredKeyFromActivity(activity: Activity): Boolean {
            val key = EXTRA_IS_PIN_REQUIRED
            if (activity.intent.hasExtra(key)) {
                activity.intent.removeExtra(key)
                return true
            }
            return false
        }

        override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
        override fun onActivityStarted(activity: Activity) {}
        override fun onActivityPaused(activity: Activity) {}
        override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
        override fun onActivityStopped(activity: Activity) {}
        override fun onActivityDestroyed(activity: Activity) {}
    }
}

结论:

该解决方案适用于我之前提到的情况,但是我尚未测试以下情况:

  • 启动时,安全活动具有启动模式singleTop | singleTask | singleInstance
  • 当应用程序被低内存的系统杀死时
  • 某人可能遇到的其他情况(如果是,请在评论部分让我知道)。